package test.demo;

import tech.waterism.modelbase.PredictBase;
import tech.waterism.modelbase.PredictResult;
import com.alibaba.fastjson.JSON;
import test.demo.gamma.Gamma;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.math3.distribution.GammaDistribution;

/**
 * 流域汇流单位线（瞬时单位线）
 *
 * @author 初京刚
 * @version 1.0
 * @date 2022-4-29
 */

public class IUH extends PredictBase {

    /**
     * 流域基流
     */
    private double Qbasic;

    /**
     * 线性水库出流系数
     */
    private double K;

    /**
     * 线性水库个数
     */
    private double n;

    /**
     * 降水时间
     */
    private Date[] floodTm;

    /**
     * 降水序列长度
     */
    private Integer floodRainRange;

    /**
     * 降水时段长
     */
    private double timeInterval;

    /**
     * 模拟总产流
     */
    private double[] runoffSim;

    /**
     * 流域面积
     */
    private double F;

    public IUH(Map<String, String> data) {
        super();
        Qbasic = Double.parseDouble(data.get("Qbasic"));
        floodTm = JSON.parseObject(data.get("dt"), Date[].class);               // input[i].data.dt
        runoffSim = JSON.parseObject(data.get("runoffSim"), double[].class);    // inout[i].data.runoffSim
        K = Double.parseDouble(data.get("K"));
        n = Double.parseDouble(data.get("n"));
        timeInterval = Double.parseDouble(data.get("clen"));                    // index.clen
        floodRainRange = runoffSim.length;
        F = Double.parseDouble(data.get("F"));
    }

    /**
     * 模型计算
     */
    public Map<String, double[]> IUHmodel() {

        // 瞬时单位线
        double[] QSim = IUHLine();

        Map<String, double[]> simulationResult = new HashMap<>();

        simulationResult.put("runoffSim", runoffSim);
        simulationResult.put("QSim", QSim);
        return simulationResult;
    }

    /**
     * 瞬时单位线
     */
    private double[] IUHLine() {
        double[] QSim = new double[floodRainRange];
        double[] iuh = new double[100];
        double CP = F / timeInterval / 3.6;

        GammaDistribution distribution = new GammaDistribution(n, K);
        for(int i = 0; i < iuh.length; i++) {
            if(i == 0) {
                iuh[i] = 0;
            } else {
                iuh[i] = distribution.cumulativeProbability(i) - distribution.cumulativeProbability(i - 1);
            }
        }

        double[][] sums = new double[floodRainRange][];
        for(int i = 0; i < floodRainRange; i++) {
            sums[i] = new double[iuh.length];
            for(int j = 0; j < iuh.length; j++) {
                sums[i][j] = runoffSim[i] * CP * iuh[j];
            }
        }

        for(int i = 0; i < floodRainRange; i++) {
            for(int j = 0; j < i + 1; j++) {
                int k = i - j;
                if(k < sums[j].length) {
                    QSim[i] = QSim[i]+sums[j][k];
                }
            }
        }


       /* double denominator;
        double[] w = new double[floodRainRange];
        if (n == 0 || n == 1) {
            denominator = K;
            for (int t = 0; t < floodRainRange; t++) {
                w[t] = 1 / denominator * Math.exp((-1) * t / K);
            }
        } else {
            denominator = K * Gamma.gamma(n);
            for (int t = 0; t < floodRainRange; t++) {
                w[t] = 1 / denominator * Math.exp((-1) * t / K) * Math.pow(t / K, n - 1);
            }
        }

        for (int i = 0; i < floodRainRange; i++) {
            for (int j = 0; j < floodRainRange; j++) {
                if (i + j < floodRainRange) {
                    QSim[j + i] = QSim[j + i] + runoffSim[i] * w[j];
                }
            }
        }*/

        for (int k = 0; k < floodRainRange; k++) {
            QSim[k] += Qbasic;
        }

        return QSim;
    }

    @Override
    public void init() {

    }

    @Override
    public PredictResult predict() {
        PredictResult result = new PredictResult();
        Map<String, double[]> map = IUHmodel();

        result.setQSim(map.get("QSim"));
        return result;
    }

    public static void main(String[] args) {
        String a = "{\"dt\":\"[\\\"2024-06-01 08:00:00\\\"]\",\"runoffSim\":\"[0.0]\",\"rSim\":\"[[0.0]]\",\"Qbasic\":\"0.0\",\"start\":\"\\\"2024-06-01 08:00:00\\\"\",\"K\":\"0.016\",\"clen\":\"6.0\",\"n\":\"61.839\",\"F\":\"-9999\"}";
        Map data = JSON.parseObject(a, Map.class);
        IUH obj = new IUH(data);
        System.out.println(obj.predict());
    }
}